﻿using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Diagnostics;

namespace XVIB360
{
    public partial class Form1 : Form
    {
        #region "XBOX 360コントローラーAPI 他"

        //[DllImport("xinput9_1_0.dll")]
        //extern static void XInputEnable(bool enable);

        [DllImport("xinput9_1_0.dll")]
        extern static uint XInputSetState(uint dwUserIndex, ref XINPUT_VIBRATION pVibration);

        [DllImport("xinput9_1_0.dll")]
        extern static uint XInputGetState(uint dwUserIndex, ref XINPUT_STATE pState);

        [StructLayout(LayoutKind.Sequential)]
        struct XINPUT_VIBRATION
        {
            public ushort wLeftMotorSpeed;
            public ushort wRightMotorSpeed;
        };

        [StructLayout(LayoutKind.Sequential)]
        struct XINPUT_STATE
        {
            public uint dwPacketNumber;
            public XINPUT_GAMEPAD Gamepad;
        };

        [StructLayout(LayoutKind.Sequential)]
        struct XINPUT_GAMEPAD
        {
            public ushort wButtons;
            public byte bLeftTrigger;
            public byte bRightTrigger;
            public short sThumbLX;
            public short sThumbLY;
            public short sThumbRX;
            public short sThumbRY;
        };

        private const uint ERROR_SUCCESS = 0;

        private const ushort XINPUT_GAMEPAD_DPAD_UP = 0x0001;
        private const ushort XINPUT_GAMEPAD_DPAD_DOWN = 0x0002;
        private const ushort XINPUT_GAMEPAD_DPAD_LEFT = 0x0004;
        private const ushort XINPUT_GAMEPAD_DPAD_RIGHT = 0x0008;
        private const ushort XINPUT_GAMEPAD_START = 0x0010;
        private const ushort XINPUT_GAMEPAD_BACK = 0x0020;
        private const ushort XINPUT_GAMEPAD_LEFT_THUMB = 0x0040;
        private const ushort XINPUT_GAMEPAD_RIGHT_THUMB = 0x0080;
        private const ushort XINPUT_GAMEPAD_LEFT_SHOULDER = 0x0100;
        private const ushort XINPUT_GAMEPAD_RIGHT_SHOULDER = 0x0200;
        private const ushort XINPUT_GAMEPAD_A = 0x1000;
        private const ushort XINPUT_GAMEPAD_B = 0x2000;
        private const ushort XINPUT_GAMEPAD_X = 0x4000;
        private const ushort XINPUT_GAMEPAD_Y = 0x8000;

        #endregion

        private VIBRATION_MODE vibmode;

        public Form1()
        {
            InitializeComponent();

            //XInputEnable(true);
            vibmode = VIBRATION_MODE.STOP;
        }

        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            //XInputEnable(false);
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            XINPUT_STATE state = new XINPUT_STATE();

            if (XInputGetState(0, ref state) == ERROR_SUCCESS)
            {
                // pressed RB button
                if ((state.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER) != 0)
                {
                    if ((state.Gamepad.wButtons & XINPUT_GAMEPAD_Y) != 0) vibmode = VIBRATION_MODE.CONTINUITY;
                    if ((state.Gamepad.wButtons & XINPUT_GAMEPAD_X) != 0) vibmode = VIBRATION_MODE.STEP;
                    if ((state.Gamepad.wButtons & XINPUT_GAMEPAD_A) != 0) vibmode = VIBRATION_MODE.STOP;
                }

                SetVibrator(vibmode);
            }
        }

        private int step_count = 0;
        private bool step_switch = false;
        private void SetVibrator(VIBRATION_MODE vibMode)
        {
            ushort leftMotor = 0, rightMotor = 0;

            switch (vibMode)
            {
                case VIBRATION_MODE.CONTINUITY:
                    leftMotor = ushort.MaxValue;
                    break;
                case VIBRATION_MODE.STEP:
                    if (step_switch)
                    {
                        leftMotor = ushort.MaxValue;
                    }
                    else
                    {
                        leftMotor = ushort.MinValue;
                    }
                    if (step_count++ > 1)
                    {
                        step_switch = !step_switch;
                        step_count = 0;
                    }
                    break;
                case VIBRATION_MODE.STOP:
                    leftMotor = ushort.MinValue;
                    break;
            }
            rightMotor = ushort.MinValue;

            XINPUT_VIBRATION xvib;
            xvib.wLeftMotorSpeed = leftMotor;
            xvib.wRightMotorSpeed = rightMotor;
            XInputSetState(0, ref xvib);
        }

        private enum VIBRATION_MODE
        {
            CONTINUITY,
            STEP,
            STOP
        }

        private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            Process.Start(linkLabel1.Text);
        }
    }
}
